package com.ruoyi.web.controller.system;

import cn.hutool.core.bean.BeanUtil;
import com.angel.mongodb.utils.Wraps;
import com.google.common.collect.Lists;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.core.service.impl.BaseService;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.viewObject.SysDeptVo;
import com.ruoyi.web.viewObject.TreeSelect;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description: 部门信息
 * @author: gankench@gmail.com
 * @time: 4/10/21 6:50 PM
 */
@RestController
@RequestMapping("/system/dept")
public class SysDeptController extends BaseController {
    @Autowired
    private BaseService deptService;

    /**
     * 获取部门列表
     */
    @PreAuthorize("@ss.hasPermi('system:dept:list')")
    @GetMapping("/list")
    public AjaxResult list(SysDeptVo dept) {
        SysDept sysDept = BeanUtil.copyProperties(dept, SysDept.class);
        List<SysDeptVo> depts = deptService.findPage(Wraps.buildBasePageQuery(sysDept, TableSupport.buildPageRequest()), SysDept.class)
                .stream()
                .map(item -> BeanUtil.copyProperties(item, SysDeptVo.class))
                .collect(Collectors.toList());
        return AjaxResult.success(depts);
    }

    /**
     * 查询部门列表（排除节点）
     */
    @PreAuthorize("@ss.hasPermi('system:dept:list')")
    @GetMapping("/list/exclude/{deptId}")
    public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) String deptId) {
        List<SysDept> depts = deptService.findListByQuery(Wraps.andWrapper(), SysDept.class);
        Iterator<SysDept> it = depts.iterator();
        while (it.hasNext()) {
            SysDept d = (SysDept) it.next();
            if (d.getId().equalsIgnoreCase(deptId)
                    || ArrayUtils.contains(d.getAncestors().toArray(), deptId)) {
                it.remove();
            }
        }
        return AjaxResult.success(depts);
    }

    /**
     * 根据部门编号获取详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:dept:query')")
    @GetMapping(value = "/{deptId}")
    public AjaxResult getInfo(@PathVariable String deptId) {
        return AjaxResult.success(BeanUtil.copyProperties(deptService.findById(deptId, SysDept.class), SysDeptVo.class));
    }

    /**
     * 获取部门下拉树列表
     */
    @GetMapping("/treeselect")
    public AjaxResult treeselect(SysDeptVo dept) {
        SysDept sysDept = BeanUtil.copyProperties(dept, SysDept.class);
        List<SysDeptVo> depts = deptService.findListByQuery(Wraps.buildBaseQuery(sysDept), SysDept.class).stream().map(e -> BeanUtil.copyProperties(e, SysDeptVo.class)).collect(Collectors.toList());
        return AjaxResult.success(buildDeptTreeSelect(depts));
    }

    /**
     * 加载对应角色部门列表树
     */
    @GetMapping(value = "/roleDeptTreeselect/{roleId}")
    public AjaxResult roleDeptTreeselect(@PathVariable("roleId") String roleId) {
        List deptIds = deptService.findPropertiesByQuery(Wraps.andWrapper().eq(SysRole::getId, roleId), SysRole.class, SysRole::getDeptIds);
        List<SysDeptVo> depts = deptService.findListByIds((List<String>) deptIds, SysDept.class).stream().map(e -> BeanUtil.copyProperties(e, SysDeptVo.class)).collect(Collectors.toList());
        AjaxResult ajax = AjaxResult.success();
        ajax.put("checkedKeys", deptIds);
        ajax.put("depts", buildDeptTreeSelect(depts));
        return ajax;
    }

    /**
     * 新增部门
     */
    @PreAuthorize("@ss.hasPermi('system:dept:add')")
    @Log(title = "部门管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysDeptVo dept) {
        SysDept sysDept = BeanUtil.copyProperties(dept, SysDept.class);
        if (UserConstants.NOT_UNIQUE.equals(deptService.findCountByQuery(Wraps.andWrapper(sysDept), SysDept.class))) {
            return AjaxResult.error("新增部门'" + dept.getDeptName() + "'失败，部门名称已存在");
        }
        dept.setCreateBy(SecurityUtils.getUsername());
        return toAjax(deptService.save(sysDept));
    }

    /**
     * 修改部门
     */
    @PreAuthorize("@ss.hasPermi('system:dept:edit')")
    @Log(title = "部门管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody SysDeptVo dept) {
        SysDept sysDept = BeanUtil.copyProperties(dept, SysDept.class);
        if (UserConstants.NOT_UNIQUE.equals(deptService.findCountByQuery(Wraps.andWrapper(sysDept), SysDept.class))) {
            return AjaxResult.error("修改部门'" + sysDept.getDeptName() + "'失败，部门名称已存在");
        } else if (sysDept.getParentId().equals(sysDept.getId())) {
            return AjaxResult.error("修改部门'" + sysDept.getDeptName() + "'失败，上级部门不能是自己");
        } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, sysDept.getStatus())
                && selectNormalChildrenDeptById(dept.getId()) > 0
        ) {
            return AjaxResult.error("该部门包含未停用的子部门！");
        }
        dept.setUpdateBy(SecurityUtils.getUsername());
        deptService.updateById(sysDept);
        return toAjax(true);
    }

    /**
     * 删除部门
     */
    @PreAuthorize("@ss.hasPermi('system:dept:remove')")
    @Log(title = "部门管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{deptId}")
    public AjaxResult remove(@PathVariable String deptId) {
        if (hasChildByDeptId(deptId)) {
            return AjaxResult.error("存在下级部门,不允许删除");
        }
        if (checkDeptExistUser(deptId)) {
            return AjaxResult.error("部门存在用户,不允许删除");
        }
        deptService.deleteById(deptId, SysDept.class);
        return toAjax(1);
    }

    /**
     * 根据ID查询所有子部门（正常状态）
     *
     * @param deptId 部门ID
     * @return 子部门数
     */
    public int selectNormalChildrenDeptById(String deptId) {
        return deptService.findCountByQuery(Wraps.andWrapper(SysDept.builder()
                        .ancestors(Lists.newArrayList(deptId))
                        .status("0")
                        .delFlag("0")
                        .build())
                , SysDept.class).intValue();
    }

    /**
     * 是否存在子节点
     *
     * @param deptId 部门ID
     * @return 结果
     */
    public boolean hasChildByDeptId(String deptId) {
        int result = deptService.findCountByQuery(Wraps.andWrapper().eq(SysDept::getParentId, deptId), SysDept.class).intValue();
        return result > 0 ? true : false;
    }

    /**
     * 查询部门是否存在用户
     *
     * @param deptId 部门ID
     * @return 结果 true 存在 false 不存在
     */
    public boolean checkDeptExistUser(String deptId) {
        int result = deptService.findCountByQuery(Wraps.andWrapper().eq(SysUser::getDeptId, deptId), SysUser.class).intValue();
        return result > 0 ? true : false;
    }

    /**
     * 构建前端所需要下拉树结构
     *
     * @param depts 部门列表
     * @return 下拉树结构列表
     */
    private List<TreeSelect> buildDeptTreeSelect(List<SysDeptVo> depts) {
        List<SysDeptVo> deptTrees = buildDeptTree(depts);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    /**
     * 构建前端所需要树结构
     *
     * @param depts 部门列表
     * @return 树结构列表
     */
    private List<SysDeptVo> buildDeptTree(List<SysDeptVo> depts) {
        List<SysDeptVo> returnList = new ArrayList<SysDeptVo>();
        List<String> tempList = new ArrayList<String>();
        for (SysDeptVo dept : depts) {
            tempList.add(dept.getId().toString());
        }
        for (Iterator<SysDeptVo> iterator = depts.iterator(); iterator.hasNext(); ) {
            SysDeptVo dept = (SysDeptVo) iterator.next();
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<SysDeptVo> list, SysDeptVo t) {
        // 得到子节点列表
        List<SysDeptVo> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysDeptVo tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<SysDeptVo> getChildList(List<SysDeptVo> list, SysDeptVo t) {
        List<SysDeptVo> tlist = new ArrayList<SysDeptVo>();
        Iterator<SysDeptVo> it = list.iterator();
        while (it.hasNext()) {
            SysDeptVo n = (SysDeptVo) it.next();
            if (StringUtils.isNotNull(n.getParentId()) && t.getId().toString().equalsIgnoreCase(n.getParentId())) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysDeptVo> list, SysDeptVo t) {
        return getChildList(list, t).size() > 0 ? true : false;
    }
}
